<?php

  class PreCompiler {
    
    
    static function load_app_models() {
      $models_array_unique = array();
    	foreach (FileHandler::list_folder_files(APP_DIR . 'model' . S) as $key => $model) {
    		$class_name = $model->filename;
        $models_array_unique['single'][$key] = Inflector::Classify($class_name);
        if (defined($class_name))
          trigger_error("Constant {$class_name} cannot be defined as it's already has been assigned.<br /> Check");
        define($class_name, $class_name);
        
        $models_array_unique['plural'][$key] = Inflector::Pluralize($models_array_unique['single'][$key]);
        if (defined($models_array_unique['plural'][$key]))
          trigger_error("Constant {$models_array_unique['plural'][$key]} cannot be defined as it's already has been assigned.<br /> Check");
        define($models_array_unique['plural'][$key], $models_array_unique['plural'][$key]);
        
    	}
      return $models_array_unique;
    }
    
    static function parse_arrays($str) {
      
      #patterns:
      $apos = '(?:\'|")';
      $php_begin = '(?:<\?php|<\?)';
      $php_end = '\?>';
      $endings = array('[' => ']');
      $replaces = array('[' => 'array(', ']' => ')');
      $return_str = '';
      $sq_str_begin = '';
      $sq_str_end = '';
      $dq_str_begin = 'ActiveString(';
      $dq_str_end = ')';
      $ac_begin = 'ctiveCollection(';
      $array_begin = 'array(';
      $array_end = ')';
      while (preg_match("/{$php_begin}/", $str, $match)) {
        $found = $match[0];
        $returned .= substr_before($str, $found);
        $returned .= $found;
        $str = substr_after($str, $found);
      /*
      while (preg_match("/(?:{$php_end}|{$apos}|.\[)/", $str, $match)) {
        $found = $match[0][(strlen($match[0]) - 1)];
        $return_str .= substr_before($str, $match[0]);
        $return_str .= isset($replaces[$found]) ? $replaces[$found] : $match[0];
        $str = substr_after($str, $found);
        if ($found == '>') {
          break;
        }
        $ending = isset($endings[$found]) ? $endings[$found] : $match[0];
        pc($found . ' <> ' . $ending, true);
        if (preg_match("/{$ending}/", $str, $match)) {
          $return_str .= substr_before($str, $ending);
          $str = substr_after($str, $ending);
          $return_str .= isset($replaces[$ending]) ? $replaces[$ending] : $match[0];
        } else {
          die("PARSE ERROR!!!!");
        }
        
      }
      */
        $as = false;
        $bs = false;
        $cs = 0;
        $ds = 0;
        $p = '';
        $c = '';
        $i = 0;
        
        // Repeats repeats repeats
        do {
          $pp = $p;
          $p = $c;
          $c = $str[$i];
          
          if ($c == '\'' && !$as && !$bs && $p != '\\') {
            $returned .= "{$sq_str_begin}'";
            $as = true;
          } elseif ($c == '"' && !$as && !$bs && $p != '\\') {
            $returned .= "{$dq_str_begin}\"";
            $bs = true;
          } elseif ($c == '\'' && $as && !$bs && $p != '\\') {
            $returned .= "'{$sq_str_end}";
            $as = false;
          } elseif ($c == '"' && !$as && $bs && $p != '\\') {
            $returned .= "\"{$dq_str_end}";
            $bs = false;
          } elseif ($c == '[' && !$as && !$bs) {
            if (!preg_match('/[a-zA-Z_0-9\]]/', $pp) && in_array($p, array('a', 'A'))) {
              $cs++;
              $returned .= $ac_begin;
            } elseif (!preg_match('/[a-zA-Z_0-9\]]/', $p)) {
              $cs++;
              $returned .= $array_begin;
            } else {
              $ds++;
              $returned .= $c;
            }
          } elseif ($c == ']' && !$as && !$bs) {
            if ($ds > 0) {
              $ds--;
              $returned .= $c;
            } else {
              $cs--;
              $returned .= $array_end;
            }
          } else {
            $returned .= $c;
          }
          $i++;
        } while (($as || $bs || !($c == '>' && $p == '?')) && ($i <= strlen($str)));
        $str = substr($str, $i);
      }
      $returned .= $str;
      return $returned;
    }
    
    
    
    # OK
    static function compile_and_require_file ($filename, $compiled_dir = COMPILED_PHP_DIR) {
      # Checking if env is test or prod; if yes do not compile file again
      if (Akrudo::if_compile_php()) {
        self::compile_file($filename, ROOT_DIR, $compiled_dir);
      }
      require($compiled_dir . $filename);
    }
    
    
    # OK
    static function compile_and_return_file ($filename) {
      $path = self::compile_file($filename);
      return file_get_contents($path);
    }
    
    
    # OK
    static function compile_file($filename, $root_dir = ROOT_DIR, $compiled_dir = COMPILED_PHP_DIR) {
      $filepath = $root_dir . $filename;
      if (!file_exists($filepath)) {
        Akrudo::raise_err($filepath . " is not present!");
      }
      $file_contents = file_get_contents($filepath);
      $file_contents = self::compile($file_contents);
      
      $filedir = dirname($filepath);
      $filedir = preg_replace('#^' . preg_quote($root_dir) . '#', '', $filedir);
      $filedir .= S;
      
      $filebase = basename($filepath);

      //$flat_filename = preg_replace('/[\/\\\\]/', '_', $filename);
      
      $compile_filedir = $compiled_dir . $filedir;
      $compile_filepath = $compile_filedir . $filebase;
      
      FileHandler::create_directory($compile_filedir);
      FileHandler::ForcedCreateFile($compile_filepath, $file_contents); 
      return $compile_filepath;
    }
    
    static function compile_folder($filename, $root_dir = ROOT_DIR, $compiled_dir = COMPILED_PHP_DIR) {
      foreach (FileHandler::list_folder_directories(ROOT_DIR . $filename) as $folder) {
        PreCompiler::compile_folder(str_replace($root_dir, '', $folder->path), $root_dir, $compiled_dir);
      }
      foreach (FileHandler::list_folder_files(ROOT_DIR . $filename) as $file) {
        $filename = str_replace($root_dir, '', $file->path);
        PreCompiler::compile_file($filename, $root_dir, $compiled_dir);
        chmod($compiled_dir . $filename, 0777);
        Akrudo::raise_info ("  compile  {$filename}... OK");
      }
      
    
    }
    
    
    
    
    
    
    
    static function compile($string) {
      
      
      
      
      $string = self::parse_arrays($string);
      //pc ($string);
      //die();
      
      
      
      
      
      
      
      
      
      //global $Nails;
      //$models = $Nails->loaded_app_models;
      # Active record's static methods
      //$active_record_static_methods = array('find', 'find_by', 'create', 'delete', 'delete_by', 'get_table_name');
      
      # Deprecated due to classkit PECL module
      /*
      # Active record's static methods without argument pattern and replacement
      $class_names_pattern = implode('|', $models['single']);
      $patterns[0] = '/(' . $class_names_pattern . ')::(' . implode('|', $active_record_static_methods) . ')\(([^\)])/';
      $replacements[0] = '\1::\2(\'\1\',\3';
      
      # Active record's static methods with argument pattern and replacement
      $patterns[1] = '/(' . $class_names_pattern . ')::(' . implode('|', $active_record_static_methods) . ')\(\)/';
      $replacements[1] = '\1::\2(\'\1\')';
      */
      
      
      # Variables starting with capital letter into Globals pattern and replacement
      $patterns[2] = '/\$([A-Z][a-zA-Z0-9_\x7f-\xff]*)/';
      $replacements[2] = '\$this->\1';
      
      
      $string = preg_replace($patterns, $replacements, $string);
      //spc ($string);
      return $string;
    }
    
    function add_to_class ($filename, $content) {
      $content;
      $filepath = $root_dir . $filename;
      if (!file_exists($filepath)) {
        Akrudo::raise_err($filepath . " is not present!");
      }
      $file_contents = file_get_contents($filepath);
      $file_contents = preg_replace('/([}][^}]+)$/', $content . '\1', $file_contents);
      
      
      FileHandler::ForcedCreateFile($filename, $file_contents);
    }
    
  }

?>